Skip to content

feat(java): thread and request resource scopes#368

Merged
pratyush618 merged 1 commit into
masterfrom
feat/java-resource-scopes
Jul 6, 2026
Merged

feat(java): thread and request resource scopes#368
pratyush618 merged 1 commit into
masterfrom
feat/java-resource-scopes

Conversation

@pratyush618

@pratyush618 pratyush618 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends the Java SDK's worker DI from two resource scopes to the full four-scope model of the cross-SDK contract.

  • ResourceScope.THREAD — one instance per worker thread, built lazily on first use, shared by every task that runs on that thread, disposed at worker shutdown. Backed by a per-name ConcurrentMap<Thread, Object>; only the owning thread touches its entry (plain get-build-put, no per-name lock — the concurrent map exists for cross-thread visibility at teardown). Disposers push onto the shared worker teardown deque, so disposal stays globally LIFO across worker- and thread-scoped instances (dependents before dependencies). If the pool retires a thread early (cached pools, autoscale), its instance is retained until worker teardown — documented, bounded by threads ever created.
  • ResourceScope.REQUEST — built fresh on every Resources.use(), never cached, disposed with the task's LIFO teardown. N uses in one task yield N instances.
  • Dependency rule (documented on ResourceContext): a factory may only depend on same-or-longer-lived resources — WORKER factories use worker resources only (error message generalized), THREAD factories use worker/thread, TASK/REQUEST factories use any scope.
  • No new public API: the scopes flow through the existing resource(name, scope, factory[, dispose]) overloads; the annotation processor is untouched.

Tests

4 new ResourceTest cases: thread instance reused across sequential tasks on a single-thread worker (created==1, disposed once at shutdown); request resource fresh per use (two uses → distinct instances, both disposed at task end); thread factory using a task-scoped dep rejected; worker factory using a thread-scoped dep rejected. 9/9 green; full ./gradlew build green.

Summary by CodeRabbit

  • New Features

    • Added support for thread-scoped resources, which can now be reused across tasks on the same worker thread and cleaned up at worker shutdown.
    • Added request-scoped resources that are created fresh for each use within a task.
  • Bug Fixes

    • Improved dependency validation and error messages when resources depend on an unsupported scope.
  • Documentation

    • Expanded lifecycle documentation to cover worker, thread, task, and request resource behavior.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds THREAD and REQUEST resource scope support to ResourceRuntime, including per-thread instance caching, a scope-dispatching resolveForTask switch, dynamic scope-name error reporting via scopeWord, request-scoped build/teardown logic, updated Javadoc across scope-related files, and new tests.

Changes

Thread/Request scope support

Layer / File(s) Summary
Scope documentation updates
sdks/java/.../ResourceContext.java, sdks/java/.../ResourceScope.java, sdks/java/.../package-info.java
Javadoc expanded to describe WORKER, THREAD, TASK, and REQUEST scope/lifetime rules and their allowed use relationships.
Thread cache and resolution helpers
sdks/java/.../ResourceRuntime.java
Adds Locale import, a threadCache map for per-thread instances, an updated threadContext, and a scopeWord helper for error messages; teardown now clears threadCache.
Scope dispatch and worker validation
sdks/java/.../ResourceRuntime.java
resolveWorker's invalid-dependency error now reports the actual conflicting scope; resolveForTask refactored into a switch dispatching WORKER, THREAD, REQUEST, and TASK handling.
Thread and request resolution implementation
sdks/java/.../ResourceRuntime.java
Adds resolveThread (per-thread caching, scope validation, LIFO teardown via workerTeardown), buildRequest, and requestContext.
Tests for thread and request scope behavior
sdks/java/src/test/java/org/byteveda/taskito/ResourceTest.java
New tests validate THREAD reuse/disposal, REQUEST per-use freshness/disposal, and ResourceException for invalid scope dependencies.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Task
  participant ResourceRuntime
  participant threadCache
  participant workerTeardown

  Task->>ResourceRuntime: resolveForTask(name)
  ResourceRuntime->>ResourceRuntime: switch on ResourceScope
  alt THREAD
    ResourceRuntime->>threadCache: lookup (name, currentThread)
    threadCache-->>ResourceRuntime: cached instance or none
    ResourceRuntime->>ResourceRuntime: build instance if absent
    ResourceRuntime->>workerTeardown: enqueue disposal (LIFO)
  else REQUEST
    ResourceRuntime->>ResourceRuntime: buildRequest(TaskScope)
    ResourceRuntime->>ResourceRuntime: registers teardown on task scope
  else WORKER/TASK
    ResourceRuntime->>ResourceRuntime: existing resolveWorker/default build path
  end
  ResourceRuntime-->>Task: resolved instance
Loading

Possibly related PRs

  • ByteVeda/taskito#340: Adds the initial WORKER/TASK resolution logic in ResourceRuntime that this PR extends with THREAD and REQUEST scope handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding thread and request resource scopes in the Java SDK.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/java-resource-scopes

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
sdks/java/src/test/java/org/byteveda/taskito/ResourceTest.java (1)

108-224: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for REQUEST-scoped dependency resolution.

The new tests cover THREAD reuse/disposal and REQUEST freshness/disposal well, plus two negative dependency checks (THREAD→TASK, WORKER→THREAD). However, REQUEST is the newest and shortest-lived scope, and its most novel code path — resolving dependencies via requestContext/buildRequest (per context snippet 3) — is untested:

  • No test verifies a REQUEST factory can successfully ctx.use(...) a WORKER/THREAD/TASK resource (positive path through requestContext).
  • No test verifies that a TASK/THREAD/WORKER factory depending on a REQUEST-scoped resource is rejected (REQUEST is shorter-lived than all of these, per the "same- or longer-lived" dependency rule).

Given requestContext's dependency-resolution logic isn't exercised by perUse's no-op factory (ctx -> new Object()) in requestResourceFreshPerUse, this is currently unverified.

Example additions
`@Test`
`@Timeout`(30)
void requestFactoryCanUseTaskScopedResource(`@TempDir` Path dir) throws Exception {
    try (Taskito queue =
            Taskito.builder().url(dir.resolve("rrqok.db").toString()).open()) {
        queue.resource("perTask", ResourceScope.TASK, ctx -> new Object());
        queue.resource("perUse", ResourceScope.REQUEST, ctx -> ctx.use("perTask"));
        // ... assert Resources.use("perUse") resolves without throwing
    }
}

`@Test`
`@Timeout`(30)
void taskFactoryCannotUseRequestScopedResource(`@TempDir` Path dir) throws Exception {
    try (Taskito queue =
            Taskito.builder().url(dir.resolve("rtrq.db").toString()).open()) {
        queue.resource("perUse", ResourceScope.REQUEST, ctx -> new Object());
        queue.resource("perTask", ResourceScope.TASK, ctx -> ctx.use("perUse"));
        // ... assert ResourceException when using "perTask"
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/java/src/test/java/org/byteveda/taskito/ResourceTest.java` around lines
108 - 224, Missing coverage for REQUEST-scoped dependency resolution: add tests
around the REQUEST path in ResourceTest to exercise requestContext/buildRequest
with real dependencies. Create one positive test where a REQUEST resource (for
example, the perUse registration) successfully ctx.use(...) a WORKER, THREAD, or
TASK resource and assert it resolves correctly, and add a negative test showing
a TASK/THREAD/WORKER factory depending on a REQUEST-scoped resource throws
ResourceException. Use the existing ResourceScope, Resources.use, and
queue.resource patterns in the new test methods to keep the scope-dependency
rules covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@sdks/java/src/test/java/org/byteveda/taskito/ResourceTest.java`:
- Around line 108-224: Missing coverage for REQUEST-scoped dependency
resolution: add tests around the REQUEST path in ResourceTest to exercise
requestContext/buildRequest with real dependencies. Create one positive test
where a REQUEST resource (for example, the perUse registration) successfully
ctx.use(...) a WORKER, THREAD, or TASK resource and assert it resolves
correctly, and add a negative test showing a TASK/THREAD/WORKER factory
depending on a REQUEST-scoped resource throws ResourceException. Use the
existing ResourceScope, Resources.use, and queue.resource patterns in the new
test methods to keep the scope-dependency rules covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c3b9f19c-0d97-4fdd-94ab-85769bf8d3d5

📥 Commits

Reviewing files that changed from the base of the PR and between 17d4f9b and 80d372f.

📒 Files selected for processing (5)
  • sdks/java/src/main/java/org/byteveda/taskito/resources/ResourceContext.java
  • sdks/java/src/main/java/org/byteveda/taskito/resources/ResourceRuntime.java
  • sdks/java/src/main/java/org/byteveda/taskito/resources/ResourceScope.java
  • sdks/java/src/main/java/org/byteveda/taskito/resources/package-info.java
  • sdks/java/src/test/java/org/byteveda/taskito/ResourceTest.java

@pratyush618 pratyush618 self-assigned this Jul 6, 2026
@pratyush618
pratyush618 merged commit 07cd25b into master Jul 6, 2026
19 checks passed
@pratyush618
pratyush618 deleted the feat/java-resource-scopes branch July 6, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant